package com.bestcem.xm.award.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.xuyanwu.spring.file.storage.Downloader;
import cn.xuyanwu.spring.file.storage.FileInfo;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.xm.award.config.FileConfig;
import com.bestcem.xm.award.config.SignConfig;
import com.bestcem.xm.award.constant.AwardAwardConstants;
import com.bestcem.xm.award.constant.ColumnConstant.AwardWinColumn;
import com.bestcem.xm.award.constant.Constants;
import com.bestcem.xm.award.constant.RedisKeyConstant;
import com.bestcem.xm.award.constant.RequestAwardConstants;
import com.bestcem.xm.award.controller.convert.AwardConvert;
import com.bestcem.xm.award.controller.dto.draw.AwardRequestDayStatsDTO;
import com.bestcem.xm.award.controller.param.award.GetWeekRequestStatsParam;
import com.bestcem.xm.award.controller.vo.award.GetWeekRequestStatsVO;
import com.bestcem.xm.award.dao.AwardAwardDao;
import com.bestcem.xm.award.dao.AwardRequestDao;
import com.bestcem.xm.award.dao.AwardRequestStatsDayDao;
import com.bestcem.xm.award.dao.AwardWinDao;
import com.bestcem.xm.award.entity.mongo.AwardTemp;
import com.bestcem.xm.award.entity.pojo.AwardAwardDO;
import com.bestcem.xm.award.entity.pojo.AwardRequestDO;
import com.bestcem.xm.award.entity.pojo.AwardWinDO;
import com.bestcem.xm.award.enums.*;
import com.bestcem.xm.award.grpc.client.DeliverGrpcService;
import com.bestcem.xm.award.grpc.service.param.award.*;
import com.bestcem.xm.award.grpc.service.param.draw.PageParam;
import com.bestcem.xm.award.grpc.service.param.requestaward.GetRequestAwardParam;
import com.bestcem.xm.award.listener.AwardEasyExcelListener;
import com.bestcem.xm.award.lua.IncreaseProjectAwardCountLua;
import com.bestcem.xm.award.mq.dto.AwardStartDTO;
import com.bestcem.xm.award.mq.dto.AwardStopDTO;
import com.bestcem.xm.award.mq.dto.TempCleanDTO;
import com.bestcem.xm.award.service.AwardAwardService;
import com.bestcem.xm.award.service.AwardCountRequestCacheService;
import com.bestcem.xm.award.service.bo.award.AwardAwardBO;
import com.bestcem.xm.award.service.bo.award.AwardWinBO;
import com.bestcem.xm.award.service.bo.award.WinDataBO;
import com.bestcem.xm.award.service.dto.AwardDataDTO;
import com.bestcem.xm.award.service.dto.awardaward.*;
import com.bestcem.xm.award.service.dto.draw.ExportWinnerDetailDTO;
import com.bestcem.xm.award.service.dto.requestaward.RequestAwardDTO;
import com.bestcem.xm.award.service.mq.send.AwardMessageService;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.domain.web.PageResultDTO;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.*;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.deliver.grpc.v1.services.CheckAwardUsedRequest;
import com.bestcem.xm.deliver.grpc.v1.services.CheckAwardUsedResponse;
import com.bestcem.xm.deliver.grpc.v1.services.GetDeliverInfoRequest;
import com.bestcem.xm.deliver.grpc.v1.services.GetDeliverInfoResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.xm.award.constant.ColumnConstant.AwardTempColumn.LEVEL;
import static com.bestcem.xm.award.constant.ColumnConstant.AwardTempColumn.NAME;
import static com.bestcem.xm.award.constant.Constants.AWARD_CODE_FILE_MAX_SIZE;
import static com.bestcem.xm.award.enums.AwardRequestStatusEnum.SEQ;
import static com.bestcem.xm.award.enums.AwardStatusEnum.*;

/**
 * 奖励抽象类
 *
 * @author sh.pei <sh.pei@idiaoyan.com>
 * @version v1.0
 * @date 2021/7/2 13:35
 */
@Slf4j
public abstract class AbstractAwardAwardService implements AwardAwardService {

    /**
     * 奖励请求记录表dao
     */
    @Autowired
    protected AwardRequestDao awardRequestDao;

    /**
     * 奖励请求统计
     */
    @Resource
    protected AwardRequestStatsDayDao awardRequestStatsDayDao;

    /**
     * 奖励元数据表dao
     */
    @Autowired
    protected AwardAwardDao awardAwardDao;

    /**
     * 奖励校验
     */
    @Autowired
    protected AwardCheck awardCheck;

    /**
     * 抽奖兑奖码dao
     */
    @Autowired
    @Qualifier("winDaoMysql")
    protected AwardWinDao awardWinDao;

    /**
     * 投放 grpc客户端
     */
    @Autowired
    protected DeliverGrpcService deliverGrpcService;

//    @Autowired
//    protected RabbitMqMessageSender mqMessageSender;

//    @Autowired
//    private RabbitMqConstantConfig rabbitMqConstantConfig;

    /**
     * oss文件配置服务
     */
    @Autowired
    protected FileConfig fileConfig;

    /**
     * oss文件服务
     */
    /*@Autowired
    protected OssService ossService;*/

    /**
     * oss数据库服务
     */
    //@Autowired
    //protected OssRecordDao ossRecordDao;

    /**
     * 签名配置
     */
    @Autowired
    protected SignConfig signConfig;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IncreaseProjectAwardCountLua increaseProjectAwardCountLua;

    @Autowired
    private AwardCountRequestCacheService awardCountRequestCacheService;

    @Value("${app.award.customAward.fileSize:10485760}")
    public Long customAwardFileSize;

    @Autowired
    private AwardMessageService awardMessageService;

    @Autowired
    private StorageService storageService;

    /**
     * 创建奖励 默认实现
     *
     * @param createAwardDTO 创建奖励入参
     * @return
     */
    @Override
    public ServiceResult<String> createAward(CreateAwardDTO createAwardDTO) {
        AwardAwardDO awardDO = AwardConvert.awardAwardBOToAwardAwardDO(createAwardDTO.getAwardAward());
        AwardAwardDO awardAwardDO = awardAwardDao.save(awardDO);
        sendMqMsg(awardAwardDO);
        return ServiceResult.success(awardAwardDO.getId());
    }

    /**
     * 发送mq消息,默认实现，子类根据需要覆盖重写
     */
    public void sendMqMsg(AwardAwardDO awardAwardDO) {
        if (awardAwardDO.getBasic() != null && awardAwardDO.getBasic().getStartTime() != null) {
            AwardStartDTO awardStartDTO = new AwardStartDTO();
            awardStartDTO.setAwardId(awardAwardDO.getId());
            awardStartDTO.setStartTime(awardAwardDO.getBasic().getStartTime());
//            try {
//                mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.AWARD_START_TOPIC, awardStartDTO, awardAwardDO.getBasic().getStartTime());
//            } catch (JsonProcessingException e) {
//                log.error("[award] 发送延迟开始奖励消息失败:" + awardAwardDO.getId(), e);
//            }
            awardMessageService.awardAwardStartSend(awardStartDTO, awardAwardDO.getBasic().getStartTime());
        }
        if (awardAwardDO.getBasic() != null && awardAwardDO.getBasic().getStopTime() != null) {
            AwardStopDTO awardStopDTO = new AwardStopDTO();
            awardStopDTO.setAwardId(awardAwardDO.getId());
            awardStopDTO.setStopTime(awardAwardDO.getBasic().getStopTime());
//            try {
//                mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.AWARD_STOP_TOPIC, awardStopDTO, awardAwardDO.getBasic().getStopTime());
//            } catch (JsonProcessingException e) {
//                log.error("[award] 发送延迟结束奖励消息失败:" + awardAwardDO.getId(), e);
//            }
            awardMessageService.awardAwardStopSend(awardStopDTO, awardAwardDO.getBasic().getStopTime());
        }

    }

    /**
     * 更新奖励 默认实现
     *
     * @param updateAwardDTO 更新奖励入参
     * @return
     */
    @Override
    public ServiceResult<String> updateAward(UpdateAwardDTO updateAwardDTO) {
        AwardAwardDO awardAwardDO = awardAwardDao.save(AwardConvert.awardAwardBOToAwardAwardDO(updateAwardDTO.getAwardAward()));
        sendMqMsg(awardAwardDO);
        return ServiceResult.success(awardAwardDO.getId());
    }

    /**
     * 更新奖励状态 默认实现
     *
     * @param updateAwardStatusDTO 更新奖励入参
     * @return
     */
    @Override
    public ServiceResult<String> updateAwardStatus(UpdateAwardStatusDTO updateAwardStatusDTO) {
        // 检查是否可以更新到新状态
        if (checkUpdateStatus(updateAwardStatusDTO.getStatus(), updateAwardStatusDTO.getOldStatus())) {
//            Update update = Update.update(STATUS, updateAwardStatusDTO.getStatus());
            AwardAwardDO update = new AwardAwardDO();
            update.setStatus(updateAwardStatusDTO.getStatus());
            // 如果是激活，保存激活时间
            if (updateAwardStatusDTO.getOldStatus() == INACTIVE.getIndex() && updateAwardStatusDTO.getStatus() == ACTIVE.getIndex()) {
                if (update.getBasic() == null) {
                    update.setBasic(new AwardAwardDO.Basic());
                }
                update.getBasic().setStartTime(DateUtil.getDate());
            }
            long modifiedCount = awardAwardDao.updateByIdAndStatus(updateAwardStatusDTO.getAwardId(), updateAwardStatusDTO.getOldStatus(), update);
            if (modifiedCount == 1) {
                return ServiceResult.success();
            }
        }
        return ServiceResult.fail("当前状态无法转移至新状态！");
    }

    /**
     * 删除奖励 默认实现
     *
     * @param param 删除奖励入参
     * @return 影响行数
     */
    @Override
    public ServiceResult<Integer> deleteAward(DeleteAwardDTO param) {
        // 根据id删除奖励
        int removeCount = awardAwardDao.remove(param.getAwardId());
        return ServiceResult.success(removeCount);
    }

    /**
     * 检查是否可以删除
     *
     * @param awardAwardDO
     * @return
     */
    @Override
    public ServiceResult<String> checkDeleteAward(AwardAwardDO awardAwardDO) {
        if (checkAwardIsInUse(awardAwardDO.getId())) {
            return ServiceResult.fail("正在被投放使用中！");
        }
        if (awardAwardDO.getStatus() == null) {
            return ServiceResult.fail("奖励状态异常！");
        }
        //未开始和已结束的奖励可以删除
        int status = awardAwardDO.getStatus().intValue();

        //是否可删除,true可删除
        boolean flag = (status == AwardStatusEnum.INACTIVE.getIndex()) || (status == AwardStatusEnum.FINISH.getIndex());
        if (!flag) {
            return ServiceResult.fail("当前状态不能删除！");
        }
        return ServiceResult.success();
    }

    /**
     * 检查奖励是否被使用中
     *
     * @param awardId
     * @return
     */
    protected boolean checkAwardIsInUse(String awardId) {
        // 是否被投放使用
        CheckAwardUsedResponse response = deliverGrpcService.checkAwardUsed(CheckAwardUsedRequest.newBuilder().setId(awardId).build());
        if (Code.OK_VALUE == response.getStatus().getCodeValue()) {
            return response.getUse();
        } else {
            log.error("检查投放是否使用中报错奖励id: {}，返回错误状态 {},返回错误信息 {}", awardId, response.getStatus().getCodeValue(), response.getStatus().getMessage());
            return true;
        }
    }

    /**
     * 查询单个奖励
     *
     * @param getAwardDTO 查询奖励入参
     * @return
     */
    @Override
    public ServiceResult<AwardDataDTO> getAward(GetAwardDTO getAwardDTO) {
        // 根据id查询奖励
        AwardAwardDO awardAwardDO = awardAwardDao.findById(getAwardDTO.getId());

        if (Objects.isNull(awardAwardDO)) {
            return ServiceResult.fail("未查到奖励信息！");
        }
        AwardDataDTO awardDataDTO = new AwardDataDTO();
        awardDataDTO.setAward(AwardConvert.awardAwardDOToAwardAwardBO(awardAwardDO));

        WinDataBO winDataBO = new WinDataBO();
        // 检查是否需要兑奖码数据
        if (checkNeedCode(awardAwardDO)) {
            //获取并设置兑奖码
            int sum = 0;
            List<AwardAwardDO.Award> awards = awardAwardDO.getAwards();
            if (!CollectionUtils.isEmpty(awards)) {
                sum = awards.stream().filter(Objects::nonNull).map(AwardAwardDO.Award::getNum).filter(Objects::nonNull).reduce(0, Integer::sum);
            }
            // 总数为0 无兑奖码
            if (sum == 0) {
                winDataBO.setStatus(WinCodeStatusEnum.NO_WIN.getIndex());
            } // 总数大于1w，单独请求
            else if (sum > Constants.AWARD_CODE_MAX) {
                winDataBO.setStatus(WinCodeStatusEnum.MANY_WIN.getIndex());
            } // 查询数据库生成返回的兑奖码数据
            else {
                String[] includeFields = new String[]{AwardWinColumn.CODE, AwardWinColumn.LEVEL, AwardWinColumn.NAME};
                String[] excludeFields = new String[]{AwardWinColumn.ID};
                List<AwardWinDO> awardWins = awardWinDao.listByAwardId(awardAwardDO.getId(), includeFields, excludeFields);
                if (CollectionUtils.isEmpty(awards)) {
                    winDataBO.setStatus(WinCodeStatusEnum.NO_WIN.getIndex());
                } else {
                    winDataBO.setStatus(WinCodeStatusEnum.SMALL_WIN.getIndex());
                    List<AwardWinBO> winBOList = new ArrayList<>();
                    for (AwardWinDO win : awardWins) {
                        if (Objects.isNull(win)) {
                            continue;
                        }
                        AwardWinBO winBO = new AwardWinBO();
                        winBO.setCode(win.getCode());
                        winBO.setLevel(win.getLevel());
                        winBO.setName(win.getName());
                        winBOList.add(winBO);
                    }
                    winDataBO.setWins(winBOList);
                }
            }
        } // 设置无兑奖码数据
        else {
            winDataBO.setStatus(WinCodeStatusEnum.NO_WIN.getIndex());
        }

        // 设置兑奖码数据
        awardDataDTO.setWinData(winDataBO);

        return ServiceResult.success(awardDataDTO);
    }

    /**
     * 列表查询奖励数据
     *
     * @param listPageAwardDTO 分页列表查询条件
     * @return
     */
    @Override
    public ServiceResult<PageResultDTO<AwardAwardBO>> listPageAward(ListPageAwardDTO listPageAwardDTO) {
        PageResultDTO<AwardAwardBO> pageResultDTO = new PageResultDTO<>();
        // 查询奖励总数据
        long count = awardAwardDao.countAwardAward(listPageAwardDTO.getOrgId(), listPageAwardDTO.getProjectId(), listPageAwardDTO.getTTypes(), listPageAwardDTO.getStatuses());
        pageResultDTO.setTotal(count);
        // 总数为0,直接返回
        if (count == 0) {
            return ServiceResult.success(pageResultDTO);
        }


        Optional<ListPageAwardDTO> optional = Optional.ofNullable(listPageAwardDTO);
        Integer page = optional.map(ListPageAwardDTO::getPageParam).map(PageParam::getPage).orElse(null);
        Integer size = optional.map(ListPageAwardDTO::getPageParam).map(PageParam::getSize).orElse(null);

        // 有分页的话, 并且分页大于最大值
        if (listPageAwardDTO.isPaging() && page != null && size != null && Math.max((page - 1) * size, 0) > count) {
            pageResultDTO.setData(new ArrayList<>());
            return ServiceResult.success(pageResultDTO);
        }
        //由于排序方式比较复杂，而单个项目奖励最多50个，所以采取将数据加载到内存后排序的方式 默认创建时间降序
        List<AwardAwardDO> awardAwardDOS = awardAwardDao.listPageAwardAward(listPageAwardDTO.getOrgId(), listPageAwardDTO.getProjectId(), listPageAwardDTO.getTTypes(), listPageAwardDTO.getStatuses(), null, null);
        // 再次检查奖励数量
        if (CollectionUtils.isEmpty(awardAwardDOS)) {
            pageResultDTO.setData(new ArrayList<>());
            return ServiceResult.success(pageResultDTO);
        }
        // 排序方式，结束的放在最后面 最近创建时间在前
        if (ListPageAwardDTO.ORDER_FINISH_LAST_THEN_CREATE_FIRST.equals(listPageAwardDTO.getOrderBy())) {
            Collections.sort(awardAwardDOS, (o1, o2) -> {
                if (o1.getStatus() == AwardStatusEnum.FINISH.getIndex() && o2.getStatus().intValue() == AwardStatusEnum.FINISH.getIndex()) {
                    return o2.getCreatedDate().compareTo(o1.getCreatedDate());
                } else if (o1.getStatus() == AwardStatusEnum.FINISH.getIndex()) {
                    return 1;
                } else if (o2.getStatus() == AwardStatusEnum.FINISH.getIndex()) {
                    return -1;
                } else {
                    return o2.getCreatedDate().compareTo(o1.getCreatedDate());
                }
            });
        }
        // 如果有要移到首位的奖励,则放到首位
        if (optional.map(ListPageAwardDTO::getFirstId).isPresent()) {
            String firstId = listPageAwardDTO.getFirstId();
            for (int i = 0; i < awardAwardDOS.size(); i++) {
                if (awardAwardDOS.get(i).getId().equals(firstId)) {
                    awardAwardDOS.add(0, awardAwardDOS.remove(i));
                    break;
                }
            }
        }
        // 有分页的话,截取分页数据
        if (listPageAwardDTO.isPaging() && page != null && size != null) {
            int left = Math.min(awardAwardDOS.size(), Math.max((page - 1) * size, 0));
            int right = Math.min(page * size, awardAwardDOS.size());
            awardAwardDOS = awardAwardDOS.subList(left, right);
        }
        if (awardAwardDOS == null || awardAwardDOS.size() == 0) {
            pageResultDTO.setData(new ArrayList<>());
        } else {
            List<AwardAwardBO> list = awardAwardDOS.stream().map(awardAward -> {
                return AwardConvert.awardAwardDOToAwardAwardBO(awardAward);
            }).collect(Collectors.toList());
            pageResultDTO.setData(list);
        }


        return ServiceResult.success(pageResultDTO);
    }

    @Override
    public ServiceResult<List<AwardAwardBO>> listAwardsByIds(List<String> awardIds) {
        if (CollectionUtil.isEmpty(awardIds)) {
            return ServiceResult.success(new ArrayList<>());
        }
        List<AwardAwardDO> awardAwardDOS = awardAwardDao.listAwardsByIds(awardIds);
        ArrayList<AwardAwardBO> list = new ArrayList();
        if (awardAwardDOS != null && awardAwardDOS.size() > 0) {
            awardAwardDOS.forEach(awardAward -> {
                list.add(AwardConvert.awardAwardDOToAwardAwardBO(awardAward));
            });
        }
        return ServiceResult.success(list);
    }

    @Override
    public ServiceResult<String> requestAward(GetRequestAwardParam getRequestAwardParam) {
        return null;
    }

    @Override
    public ServiceResult<String> doRequestAward(RequestAwardDTO requestAwardDTO) {
        return null;
    }

    /**
     * 奖励创建和修改时的通用参数校验
     *
     * @param awardAward 奖励数据
     * @return 校验结果
     */
    @Override
    public ServiceResult<String> commonCheckAward(AwardAwardBO awardAward) {
        if (Objects.isNull(awardAward)) {
            return ServiceResult.fail("奖励信息为空！");
        }
        // 校验projectId
        if (Objects.isNull(awardAward.getProjectId())) {
            return ServiceResult.fail("项目id为空！");
        }
        // 校验公司id
        if (Objects.isNull(awardAward.getOrgId())) {
            return ServiceResult.fail("公司id为空！");
        }
        // 校验奖励名称
        if (StringUtils.isBlank(awardAward.getName())) {
            return ServiceResult.fail("奖励名称为空！");
        }
        // 检查机构id格式
        boolean checkObjectId = StringUtil.checkObjectId(awardAward.getOrgId());
        if (!checkObjectId) {
            return ServiceResult.fail("orgId格式错误");
        }
        // 检查项目id格式
        if (!StringUtil.checkObjectId(awardAward.getProjectId())) {
            return ServiceResult.fail("项目id格式错误");
        }
        // 校验奖励类型
        AwardTypeEnum awardType = EnumUtil.getEnumByIndex(AwardTypeEnum.class, awardAward.getTType());
        if (Objects.isNull(awardType)) {
            return ServiceResult.fail("奖励类型错误！");
        }
        // 设置奖励为未激活状态
        awardAward.setStatus(AwardStatusEnum.INACTIVE.getIndex());
        if (awardAward.getName().length() > Constants.AWARD_NAME_MAX_LENGTH) {
            return ServiceResult.fail(String.format("奖励名称长度大于%d！", Constants.AWARD_NAME_MAX_LENGTH));
        }
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<String> checkAwardCount(String orgId, String projectId) {
        String key = String.format(RedisKeyConstant.AWARD_COUNT_PROJECT, orgId, projectId);
        Long count = 0L;
        String countStr = redisService.getString(key);
        if (countStr == null) {
            count = initProjectAwardCount(orgId, projectId);
        } else {
            count = Long.valueOf(countStr);
        }
        if (count >= Constants.AWARD_MAX_COUNT_PER_PROJECT) {
            return ServiceResult.fail("奖励数量已达到最大值");
        }
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<String> checkDuplicateName(String name, String projectId, String awardId) {
        if (awardAwardDao.findDuplicateName(name, projectId, awardId) > 0) {
            return ServiceResult.fail("名称已存在！");
        }
        return ServiceResult.success();
    }

    /**
     * 各个奖励类独立的校验 的默认实现
     *
     * @param awardAward 奖励数据
     * @return 校验结果
     */
    @Override
    public ServiceResult<String> independentCheckAward(AwardAwardBO awardAward) {
        return ServiceResult.success();
    }

    /**
     * 校验微信优惠券和阿里优惠券页面配置
     *
     * @param awardAward 奖励数据
     * @return 校验结果
     */
    public ServiceResult<String> doCheckWechatPage(AwardAwardBO awardAward) {
        Optional<AwardAwardBO> optional = Optional.ofNullable(awardAward);
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getStartTime).isPresent() || awardAward.getBasic().getStartTime().getTime() < DateUtil.now().getTime()) {
            awardAward.getBasic().setStartTime(DateUtil.getDate());
        }
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getStopTime).isPresent()) {
            return ServiceResult.fail("奖励结束时间缺失！");
        }
        if (awardAward.getBasic().getStopTime().compareTo(awardAward.getBasic().getStartTime()) < 0) {
            return ServiceResult.fail("结束时间不能在开始时间或当前时间之前!");
        }
        // 检查手机端页面配置
        ServiceResult<String> checkMobile = checkPageFront(optional.map(AwardAwardBO::getPage).map(AwardAwardBO.Page::getMobile));
        if (!checkMobile.isSuccess()) {
            return checkMobile;
        }
        // 检查电脑端页面配置
        ServiceResult<String> checkPc = checkPageFront(optional.map(AwardAwardBO::getPage).map(AwardAwardBO.Page::getPc));
        if (!checkPc.isSuccess()) {
            return checkPc;
        }
        awardAward.setIssue(null);
        awardAward.setAwards(null);
        return ServiceResult.success();
    }

    /**
     * 校验优惠券页面配置 二维码必传 text非必填 logo非必填 bg必穿
     *
     * @param pageFront 页面配置
     * @return 校验结果
     */
    protected ServiceResult<String> checkPageFront(Optional<AwardAwardBO.PageFront> pageFront) {
        //校验二维码
        if (!pageFront.map(AwardAwardBO.PageFront::getQr).map(AwardAwardBO.PageFrontQr::getPath).isPresent()) {
            return ServiceResult.fail("二维码路径为空！");
        }
        // 校验背景
        if (!pageFront.map(AwardAwardBO.PageFront::getBg).map(AwardAwardBO.PageFrontBg::getColor).isPresent()
                && !pageFront.map(AwardAwardBO.PageFront::getBg).map(AwardAwardBO.PageFrontBg::getPath).isPresent()) {
            return ServiceResult.fail("请设置页面背景！");
        }
        // 背景颜色，color与id+path只能二选一，有color就不存储id+path
        if (pageFront.map(AwardAwardBO.PageFront::getBg).map(AwardAwardBO.PageFrontBg::getColor).isPresent()) {
            pageFront.map(AwardAwardBO.PageFront::getBg).get().setPath(null);
            pageFront.map(AwardAwardBO.PageFront::getBg).get().setId(null);
        }
        return ServiceResult.success();
    }

    /**
     * 通用校验
     *
     * @param getRequestAwardParam 校验参数
     * @return 校验结果
     */
    protected RequestAwardDTO commonValid(GetRequestAwardParam getRequestAwardParam) {
        RequestAwardDTO requestAwardDTO = new RequestAwardDTO();
        requestAwardDTO.setDeliver(getRequestAwardParam.getDeliver());
        // 校验award_id
        String awardId = getRequestAwardParam.getDeliver().getAwardId();
        // awardId为空,查询获取awardId
        if (StringUtils.isBlank(awardId)) {
            if (StringUtils.isNotBlank(getRequestAwardParam.getDeliver().getDeliverId())) {
                // deliverId不为空,获取awardId
                GetDeliverInfoRequest.Builder builder = GetDeliverInfoRequest.newBuilder();
                builder.setId(getRequestAwardParam.getDeliver().getDeliverId());
                GetDeliverInfoResponse deliverResponse = deliverGrpcService.getDeliver(builder.build());
                if (log.isInfoEnabled()) {
                    log.info("[award] 查询投放信息: deliverId:{}, status:{}, msg:{}", getRequestAwardParam.getDeliver().getDeliverId(), deliverResponse.getStatus().getCodeValue(), deliverResponse.getStatus().getMessage());
                }
                if (deliverResponse.getStatus().getCodeValue() != Code.OK_VALUE) {
                    awardId = Constants.BLANK;
                } else {
                    if (log.isDebugEnabled()) {
                        log.debug("[award] 投放信息:{}", JSON.toJSONString(deliverResponse.getDeliver()));
                    }
                    awardId = deliverResponse.getDeliver().getAwardId();
                }
            } else {
                // deliverId为空,awardId为空
                awardId = Constants.BLANK;
            }
        }
        if (StringUtils.isBlank(awardId)) {
            requestAwardDTO.setStatus(Boolean.FALSE);
            requestAwardDTO.setMessage(RequestAwardConstants.DELIVER_WITHOUT_AWARD);
            return requestAwardDTO;
        }
        // 校验deliver_id是否匹配
        if (!getRequestAwardParam.getDeliver().getDeliverId().equals(getRequestAwardParam.getSurvey().getDeliverId())) {
            requestAwardDTO.setStatus(Boolean.FALSE);
            requestAwardDTO.setMessage(RequestAwardConstants.DELIVER_ID_DIFFERENT);
            return requestAwardDTO;
        }
        // 校验奖励是否生效
        AwardAwardDO awardAwardDO = awardAwardDao.findByAwardIdAndStatus(awardId, ACTIVE.getIndex());
        if (Validator.isNull(awardAwardDO)) {
            requestAwardDTO.setStatus(Boolean.FALSE);
            requestAwardDTO.setMessage(RequestAwardConstants.AWARD_EXPIRE);
            return requestAwardDTO;
        }
        // 返回AWARD_AWARD数据
        requestAwardDTO.setAwardAwardDO(awardAwardDO);
        // AWARD_REQUEST
        AwardRequestDO request = this.paramToRequest(getRequestAwardParam);
        request.setAwardId(awardId);
        request.setIp(getRequestAwardParam.getIp());
        request.setTty(getRequestAwardParam.getDeviceType());
        // 校验一个seq只能抽奖一次
        long count = awardRequestDao.countAwardRequestBySurveySeqAndDeliverId(
                getRequestAwardParam.getSurvey().getSeq(), getRequestAwardParam.getDeliver().getDeliverId());
        if (count > Constants.ZERO) {
            request.setStatus(SEQ.getIndex());
            awardRequestDao.insert(request);
            requestAwardDTO.setStatus(Boolean.FALSE);
            requestAwardDTO.setMessage(RequestAwardConstants.SURVEY_AWARD_REPEAT);
            return requestAwardDTO;
        }
        requestAwardDTO.setRemoteIp(getRequestAwardParam.getIp());
        requestAwardDTO.setTty(getRequestAwardParam.getDeviceType());
        requestAwardDTO.setVt(getRequestAwardParam.getVisitedCount());
        // 返回AWARD_REQUEST数据
        requestAwardDTO.setAwardRequestDO(request);
        requestAwardDTO.setStatus(Boolean.TRUE);
        requestAwardDTO.setMessage(Constants.BLANK);
        return requestAwardDTO;
    }

    @Override
    public ServiceResult<GetRequestStatsDTO> getRequestStats(GetRequestStatsParam getRequestStatsParam) {
        String awardId = getRequestStatsParam.getAwardId();
        String orgId = getRequestStatsParam.getOrgId();
        String deliverId = getRequestStatsParam.getDeliverId();
        // 确认这是本组织的奖励
        AwardAwardDO awardAwardDO = awardAwardDao.findByAwardIdAndOrgId(awardId, orgId);
        if (Validator.isNull(awardAwardDO)) {
            return ServiceResult.fail(AwardAwardConstants.AWARD_IS_NULL);
        }
        long[] requestCount = awardCountRequestCacheService.getRequestTotalAndPassCount(awardId);

        // 查询奖励请求数量
        GetRequestStatsDTO getRequestStatsDTO = new GetRequestStatsDTO();
        // 查询不到奖励请求数量 置为0
        getRequestStatsDTO.setTotalCount(Math.toIntExact(requestCount[0]));
        getRequestStatsDTO.setPassCount(Math.toIntExact(requestCount[1]));
        return ServiceResult.success(getRequestStatsDTO);
    }

    @Override
    public ServiceResult<GetWeekRequestStatsVO> getWeekRequestStats(GetWeekRequestStatsParam getWeekRequestStatsParam) {
        String awardId = getWeekRequestStatsParam.getAwardId();
        String orgId = getWeekRequestStatsParam.getOrgId();
        // 确认这是本组织的奖励
        AwardAwardDO awardAwardDO = awardAwardDao.findByAwardIdAndOrgId(awardId, orgId);
        if (Validator.isNull(awardAwardDO)) {
            return ServiceResult.fail(AwardAwardConstants.AWARD_IS_NULL);
        }
        Date now = new Date();
        List<AwardRequestDayStatsDTO> ret = awardCountRequestCacheService.getRequestTotalAndPassDayCount(awardId, cn.hutool.core.date.DateUtil.offsetDay(now, -6), 6);
        if (ret != null && ret.size() > 0) {
            ret.stream().forEach(awardRequestDayStatsDTO -> awardRequestDayStatsDTO.setDay(awardRequestDayStatsDTO.getDay().replaceAll("-", "/")));
        }

        // 返回数据
        GetWeekRequestStatsVO getWeekRequestStatsVO = new GetWeekRequestStatsVO();
        getWeekRequestStatsVO.setStats(ret);
        return ServiceResult.success(getWeekRequestStatsVO);
    }

    @Override
    public ServiceResult<String> deleteAttachment(DeleteAttachmentParam deleteAttachmentParam) {
        String attachmentId = deleteAttachmentParam.getAttachmentId();
        String awardId = deleteAttachmentParam.getAwardId();
        // 存在奖励id 查询附件是否存在
        if (StringUtils.isNotBlank(awardId)) {
            // 根据附件id 奖励id 查询奖励
            AwardAwardDO award = awardAwardDao.findByAttachmentIdAndAwardId(attachmentId, awardId);
            if (Validator.isNull(award)) {
                return ServiceResult.fail(AwardAwardConstants.ATTACHMENT_NOT_EXIST);
            }
        }
        // 删除oss文件,原先python库的不处理
        /*OssRecordEntity entity = ossRecordDao.findById(attachmentId);

        String key = Optional.ofNullable(entity).map(OssRecordEntity::getOssKey).orElse(Constants.BLANK);
        long deleteCount = Constants.ZERO;
        if (StringUtils.isNotBlank(key)) {
            //deleteCount = ossService.deleteByKey(key);
        }*/
        long deleteCount = storageService.deleteById(attachmentId) ? 1 : 0;
        // 不存在奖励id 只删除oss文件 返回结果
        if (StringUtils.isBlank(awardId)) {
            return deleteCount > Constants.ZERO
                    ? ServiceResult.success(attachmentId)
                    : ServiceResult.fail(AwardAwardConstants.DELETE_ATTACHMENT_FAIL);
        }
        // 根据附件id 奖励id 删除附件
        AwardAwardDO awardAwardDO = awardAwardDao.deleteAttachmentByAttachmentIdAndAwardId(attachmentId, awardId);
        return Validator.isNotNull(awardAwardDO)
                ? ServiceResult.success(attachmentId)
                : ServiceResult.fail(AwardAwardConstants.DELETE_ATTACHMENT_FAIL);
    }

    @Override
    public ServiceResult<FileInfo> uploadAttachment(MultipartFile file) {
        if (Validator.isNull(file)) {
            return ServiceResult.fail(AwardAwardConstants.ATTACHMENT_NOT_EXIST);
        }
        if (file.getSize() > customAwardFileSize) {
            return ServiceResult.failWithCode(ResourceErrorCodeEnum.FILE_TOO_LARGE, AwardAwardConstants.CUSTOM_AWARD_FILE_TOO_LARGE);
        }
        String fileType = FileUtil.getFileExtension(file.getOriginalFilename());
        boolean fileTypeSupport = Constants.CUSTOM_AWARD_ATTACH_FILE_TYPES.stream().anyMatch(fileName -> fileName.equalsIgnoreCase(fileType));
        if (!fileTypeSupport) {
            return ServiceResult.failWithCode(ValidationErrorCodeEnum.FILE_TYPE_NOT_RIGHT, AwardErrorMsgEnum.FILE_NOT_SUPPORT.getMsg());
        }
        try {
            String originalFilename = file.getOriginalFilename();
            File tempFile = new File(fileConfig.getTempFileDir() + originalFilename);
            file.transferTo(tempFile);
            /*OssRecordEntity entity = ossService.uploadSimpleFileReturnEntity(tempFile, originalFilename,
                    OssPathEnum.AWARD, Constants.ZERO, null, "定制奖励附件上传");*/
            FileInfo fileInfo = storageService.upload(tempFile, originalFilename, OssPathEnum.AWARD.getPath(), new Dict());
            if (Validator.isNotNull(tempFile)) {
                tempFile.delete();
            }
            //return ServiceResult.success(entity);
            return ServiceResult.success(fileInfo);
        } catch (IOException e) {
            log.error("[Award] 上传附件失败", e);
        }
        return ServiceResult.fail(AwardAwardConstants.ATTACHMENT_NOT_EXIST);
    }

    @Override
    public ServiceResult<AwardsDTO> listAwardsLevelNames(ListAwardsLevelNamesParam listAwardsLevelNamesParam) {
        AwardsDTO awardsDTO = new AwardsDTO();
        List<Integer> levels = new ArrayList<>();
        List<String> names = new ArrayList<>();

        String tempId = listAwardsLevelNamesParam.getTempId();
        String awardId = listAwardsLevelNamesParam.getAwardId();
        String orgId = listAwardsLevelNamesParam.getOrgId();
        boolean queryLevel = listAwardsLevelNamesParam.isQueryLevel();
        boolean queryName = listAwardsLevelNamesParam.isQueryName();

        // awardId、orgId不为空,从AWARD_AWARD表获取奖项信息
        if (StringUtils.isNotBlank(awardId) && StringUtils.isNotBlank(orgId)) {
            if (queryLevel) {
                levels = awardAwardDao.queryDistinctAwardLevel(awardId, orgId);
            }
            if (queryName) {
                names = awardAwardDao.queryDistinctAwardName(awardId, orgId);
            }
        }

        awardsDTO.setLevel(levels);
        awardsDTO.setName(names);
        return ServiceResult.success(awardsDTO);
    }

    @Override
    @Deprecated
    public ServiceResult<String> importDrawCodes(ImportDrawCodesParam importDrawCodesParam) {
        // 预留功能,目前没有地方调用
        // 生成12位数字+字母的字符串
        String tempId = RandomStringUtils.random(Constants.TWELVE, true, true);
        //添加到延迟队列来清除此temp_id信息 七天
        TempCleanDTO tempCleanDTO = new TempCleanDTO();
        tempCleanDTO.setTempId(tempId);
//        try {
//            mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(),
//                    rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.TEMP_CLEAN_TOPIC,
//                    tempCleanDTO, Constants.SEVEN_DAYS_UNIT_MILLIS);
//        } catch (JsonProcessingException e) {
//            log.error("[Award] 发送延迟清除此temp_id信息消息失败:tempId {}", tempId, e);
//        }
        //stream mq /2022.05.03
        awardMessageService.awardTempCleanSend(tempCleanDTO, Constants.SEVEN_DAYS_UNIT_MILLIS);
        // OSS 文件url
        String ossUrl = importDrawCodesParam.getUrl();
        // OSS 获取上传的文件 读取数据
        List<AwardTemp> tempList = this.readAwardTempExcel(tempId, ossUrl);
        if (CollectionUtil.isEmpty(tempList)) {
            ServiceResult.fail(AwardAwardConstants.IMPORT_DRAW_CODE_FAIL);
        }
        // 历史逻辑,不支持超过1w条数据,方法预留
        if (tempList.size() >= Constants.TEN_THOUSAND) {
            return ServiceResult.fail(AwardAwardConstants.IMPORT_WIN_RECORD_OVER_TEN_THOUSAND);
        }
        // 加锁 根据tempId删除AWARD_TEMP表所有数据,再添加本次上传的数据
        String lockKey = String.format(RedisKeyConstant.TEMP_ID_LOCK_KEY, tempId);
        long insertCount = 0;
        redisService.lock(lockKey);
        try {
            // awardTempDao.deleteByTempId(tempId);
            // insertCount = awardTempDao.insertMany(tempList);
        } finally {
            redisService.unlock(lockKey);
        }
        return insertCount > Constants.ZERO
                ? ServiceResult.success(tempId)
                : ServiceResult.fail(AwardAwardConstants.IMPORT_DRAW_CODE_FAIL);
    }

    @Override
    public ServiceResult<List<ExportWinnerDetailDTO>> importDrawCodesLessThanTenThousand(MultipartFile file) {
        if (Validator.isNull(file)) {
            return ServiceResult.fail(AwardAwardConstants.UPLOAD_FAIL);
        }
        if (file.getSize() > AWARD_CODE_FILE_MAX_SIZE) {
            return ServiceResult.failWithCode(ResourceErrorCodeEnum.FILE_TOO_LARGE, AwardAwardConstants.DRAW_CODE_FILE_TOO_LARGE);
        }
        // 文件名
        String filename = file.getOriginalFilename();
        if (log.isInfoEnabled()) {
            log.info("[Award] 兑奖码文件名:{}", filename);
        }
        if (StringUtils.isBlank(filename)) {
            return ServiceResult.fail(AwardErrorMsgEnum.FILE_NOT_SUPPORT.getMsg());
        }
        // 后缀名校验
        if (!(filename.endsWith(Constants.SUFFIX_XLSX) || filename.endsWith(Constants.SUFFIX_XLS) || filename.endsWith(Constants.SUFFIX_CSV))) {
            return ServiceResult.fail(ValidationErrorCodeEnum.FILE_TYPE_NOT_RIGHT, AwardErrorMsgEnum.FILE_NOT_SUPPORT.getMsg());
        }
        // 读取兑奖码数据
        ServiceResult<List<ExportWinnerDetailDTO>> readResult;
        if ((filename.endsWith(Constants.SUFFIX_XLSX) || filename.endsWith(Constants.SUFFIX_XLS))) {
            readResult = this.readDrawCodesXlsxOrXls(file);
        } else if (filename.endsWith(Constants.SUFFIX_CSV)) {
            readResult = this.readDrawCodesCsv(file);
        } else {
            return ServiceResult.fail(ValidationErrorCodeEnum.FILE_TYPE_NOT_RIGHT, AwardErrorMsgEnum.FILE_NOT_SUPPORT.getMsg());
        }
        if (!readResult.isSuccess()) {
            return ServiceResult.fail(readResult.getMsg());
        }
        // 读取到的数据
        List<ExportWinnerDetailDTO> list = readResult.getData();
        if (CollectionUtil.isEmpty(list)) {
            return ServiceResult.fail(AwardAwardConstants.DRAW_CODE_NULL);
        }
        // 大于1w条数据,不处理
        if (CollectionUtil.isNotEmpty(list) && list.size() > Constants.TEN_THOUSAND) {
            return ServiceResult.fail(AwardAwardConstants.DRAW_CODE_MORE_THAN_TEN_THOUSAND);
        }
        return ServiceResult.success(list);
    }

    @Override
    @Deprecated
    public ServiceResult<FileInfoDTO> exportDrawCodes(ExportDrawCodesParam exportDrawCodesParam) {
        // 预留功能,目前没有地方调用
        // 奖励id
        String awardId = Optional.ofNullable(exportDrawCodesParam).map(ExportDrawCodesParam::getId).orElse(Constants.BLANK);
        // 组织id
        String orgId = Optional.ofNullable(exportDrawCodesParam).map(ExportDrawCodesParam::getOrgId).orElse(Constants.BLANK);
        // AWARD_TEMP表temp_id
        String tempId = Optional.ofNullable(exportDrawCodesParam).map(ExportDrawCodesParam::getTempId).orElse(Constants.BLANK);

        List<ExportWinnerDetailDTO> winnerDetailDTOList = new ArrayList<>();
        if (StringUtils.isNotBlank(awardId) && StringUtils.isNotBlank(orgId)) {
            // 确认这是本组织的奖励
            AwardAwardDO awardAwardDO = awardAwardDao.findByAwardIdAndOrgId(awardId, orgId);
            if (Validator.isNull(awardAwardDO)) {
                return ServiceResult.fail(AwardAwardConstants.AWARD_IS_NULL);
            }
            List<AwardWinDO> winList = awardWinDao.listByAwardId(awardId, new String[]{AwardWinColumn.CODE, LEVEL, NAME}
                    , new String[]{AwardWinColumn.ID});
            // 获取兑奖码 奖项等级 奖项名称 三个字段内容
            winnerDetailDTOList = this.getWinDetail(winList);
        }
        if (CollectionUtil.isEmpty(winnerDetailDTOList)) {
            return ServiceResult.fail(AwardAwardConstants.WIN_RECORD_NOT_EXIST);
        }

        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String fileName = "兑奖码数据_" + date + ".xlsx";
        // 生成Excel数据
        byte[] excelBytes = ExcelExportUtil.createExcelStream(winnerDetailDTOList, ExportWinnerDetailDTO.class);
        //String ossUrl = ossService.uploadTempFile(excelBytes, fileName, OssPathEnum.TEMP_AWARD, Constants.OSS_TEMP_EXPIRE_SECOND, "奖励-兑奖码文件生成");
        String ossUrl = storageService.upload(excelBytes, fileName, OssPathEnum.TEMP_AWARD.getPath(), new Dict()).getUrl();
        return ServiceResult.success(new FileInfoDTO("", fileName, ossUrl));
    }

    /**
     * 剔除多余参数,只返回兑奖码 奖项等级 奖项名称 三个字段内容
     *
     * @param sourceList 兑奖码信息
     * @param <T>        类型
     * @return 兑奖码、奖项等级、奖项名称列表
     */
    private <T> List<ExportWinnerDetailDTO> getWinDetail(List<T> sourceList) {
        return sourceList.stream().map(win -> {
            ExportWinnerDetailDTO winnerDetailDTO = new ExportWinnerDetailDTO();
            BeanUtil.copyProperties(win, winnerDetailDTO);
            return winnerDetailDTO;
        }).collect(Collectors.toList());
    }

    /**
     * oss文件 读取数据
     *
     * @param tempId AWARD_TEMP表 temp_id
     * @param ossUrl oss文件url
     * @return 读取到的temp表兑奖码数据
     */
    private List<AwardTemp> readAwardTempExcel(String tempId, String ossUrl) {
        List<AwardTemp> tempList = new ArrayList<>();
        // 获取oss文件流
        Downloader downloader = storageService.downloadByUrl(ossUrl);
        if (downloader != null) {
            //try (InputStream inputStream = ossService.downloadByUrl(ossUrl)) {
            try (InputStream inputStream = new ByteArrayInputStream(downloader.bytes())) {
                // 读取数据
                ExcelReader excelReader = ExcelUtil.getReader(inputStream);
                List<List<Object>> read = excelReader.read(1, excelReader.getRowCount());
                for (List<Object> objects : read) {
                    AwardTemp awardTemp = new AwardTemp();
                    awardTemp.setTempId(tempId);
                    awardTemp.setCode(Convert.toStr(objects.get(0)));
                    awardTemp.setLevel(Convert.toInt(objects.get(1)));
                    awardTemp.setName(Convert.toStr(objects.get(2)));
                    tempList.add(awardTemp);
                }
            } catch (IOException e) {
                log.error("[Award] 获取oss文件流失败:url {}", ossUrl, e);
            }
        }
        return tempList;
    }

    /**
     * 上传兑奖码文件 读取数据(xlsx xls格式)
     *
     * @param file 上传文件
     * @return 兑奖码数据
     */
    private ServiceResult<List<ExportWinnerDetailDTO>> readDrawCodesXlsxOrXls(MultipartFile file) {
        List<ExportWinnerDetailDTO> list = new ArrayList<>();
        // 获取文件流
        try (InputStream inputStream = file.getInputStream()) {
            AwardEasyExcelListener<ExportWinnerDetailDTO> excelListener = new AwardEasyExcelListener<>();
            EasyExcel.read(inputStream, ExportWinnerDetailDTO.class, excelListener).sheet().doRead();

            // 表头校验
            Map<Integer, String> headMap = excelListener.getHeadMap();
            String codeTitle = headMap.get(0);
            String levelTitle = headMap.get(1);
            String nameTitle = headMap.get(2);
            if (!codeTitle.equals(AwardAwardConstants.TITLE_CODE) || !levelTitle.equals(AwardAwardConstants.TITLE_LEVEL)
                    || !nameTitle.equals(AwardAwardConstants.TITLE_NAME)) {
                return ServiceResult.fail(AwardAwardConstants.FILE_NOT_MATCH);
            }
            // 数据校验
            if (CollectionUtils.isEmpty(excelListener.getResult())) {
                return ServiceResult.fail(AwardAwardConstants.READ_DRAW_CODE_FAIL);
            }
            for (ExportWinnerDetailDTO exportWinnerDetailDTO : excelListener.getResult()) {
                String code = StringUtil.strTrim(exportWinnerDetailDTO.getCode());
                String level = StringUtil.strTrim(exportWinnerDetailDTO.getLevel());
                String name = StringUtil.strTrim(exportWinnerDetailDTO.getName());
                if (StringUtils.isBlank(code) || StringUtils.isBlank(level) || StringUtils.isBlank(name)
                        || code.length() > Constants.DrawAwardParamsRule.AWARD_WIN_CODE_MAX_LENGTH) {
                    continue;
                }
                if (!code.matches(RegTypes.AWARD_CODE)) {
                    return ServiceResult.fail(AwardAwardConstants.DRAW_CODE_FORMAT_ERROR);
                }
                list.add(exportWinnerDetailDTO);
            }
        } catch (Exception e) {
            log.error("[Award] 兑奖码文件 读取数据失败", e);
        }
        return ServiceResult.success(list);
    }

    /**
     * 上传兑奖码文件 读取数据(csv格式)
     *
     * @param file 上传文件
     * @return 兑奖码数据
     */
    private ServiceResult<List<ExportWinnerDetailDTO>> readDrawCodesCsv(MultipartFile file) {
        List<ExportWinnerDetailDTO> list = new ArrayList<>();
        try {
            String originalFilename = file.getOriginalFilename();
            Assert.notNull(originalFilename, "error");
            String[] prefixAndSuffix = originalFilename.split("\\.");
            File tempFile = new File(fileConfig.getTempFileDir() + UUID.randomUUID() + "." + prefixAndSuffix[1]);
            file.transferTo(tempFile);
            CsvReader reader = CsvUtil.getReader();
            CsvData data = reader.read(tempFile);
            List<CsvRow> rows = data.getRows();
            // 标题校验
            List<String> titleList = rows.get(0).getRawList();
            if (CollectionUtil.isEmpty(titleList) || titleList.size() < 3) {
                return ServiceResult.fail(AwardAwardConstants.FILE_NOT_MATCH);
            }
            if (CollectionUtil.isNotEmpty(titleList)) {
                String codeTitle = StringUtil.strTrim(titleList.get(0));
                String levelTitle = StringUtil.strTrim(titleList.get(1));
                String nameTitle = StringUtil.strTrim(titleList.get(2));
                if (!codeTitle.contains(AwardAwardConstants.TITLE_CODE) || !levelTitle.contains(AwardAwardConstants.TITLE_LEVEL)
                        || !nameTitle.contains(AwardAwardConstants.TITLE_NAME)) {
                    return ServiceResult.fail(AwardAwardConstants.FILE_NOT_MATCH);
                }
            }
            // 数据
            if (log.isInfoEnabled()) {
                log.info("[Award] csv数据行数:{}", Validator.isNotNull(rows) ? rows.size() : 0);
            }
            for (int i = 1; i < rows.size(); i++) {
                List<String> dataList = rows.get(i).getRawList();
                if (log.isInfoEnabled()) {
                    log.info("[Award] csv读取第{}行数据:{}", i, Validator.isNotNull(dataList) ? dataList.toString() : "null");
                }
                if (CollectionUtil.isEmpty(dataList) || dataList.size() < 3) {
                    continue;
                }
                String code = StringUtil.strTrim(dataList.get(0));
                String level = StringUtil.strTrim(dataList.get(1));
                String name = StringUtil.strTrim(dataList.get(2));
                if (StringUtils.isBlank(code) || StringUtils.isBlank(level) || StringUtils.isBlank(name)
                        || code.length() > Constants.DrawAwardParamsRule.AWARD_WIN_CODE_MAX_LENGTH) {
                    continue;
                }
                if (!code.matches(RegTypes.AWARD_CODE)) {
                    return ServiceResult.fail(AwardAwardConstants.DRAW_CODE_FORMAT_ERROR);
                }
                ExportWinnerDetailDTO dto = new ExportWinnerDetailDTO();
                dto.setCode(code);
                dto.setLevel(level);
                dto.setName(name);
                list.add(dto);
            }
            if (log.isInfoEnabled()) {
                log.info("[Award] csv读取数据:{}", Validator.isNotNull(list) ? list.toString() : "null");
            }
            if (Validator.isNotNull(tempFile)) {
                tempFile.delete();
            }
        } catch (Exception e) {
            log.error("[Award] 兑奖码文件 读取数据失败", e);
        }
        return ServiceResult.success(list);
    }

    /**
     * 检查是否可以更新奖励状态 默认实现
     *
     * @param newStatus 新状态
     * @param oldStatus 老状态
     * @return
     */
    public boolean checkUpdateStatus(int newStatus, int oldStatus) {
        if (AwardStatusEnum.INACTIVE.getIndex() == oldStatus) {
            return ACTIVE.getIndex() == newStatus || FINISH.getIndex() == newStatus;
        } else if (ACTIVE.getIndex() == oldStatus) {
            return PAUSE.getIndex() == newStatus || FINISH.getIndex() == newStatus;
        } else if (PAUSE.getIndex() == oldStatus) {
            return ACTIVE.getIndex() == newStatus || FINISH.getIndex() == newStatus;
        }
        return false;
    }

    /**
     * 参数转换
     *
     * @param getRequestAwardParam 请求参数
     * @return AwardRequest
     */
    private AwardRequestDO paramToRequest(GetRequestAwardParam getRequestAwardParam) {
        AwardRequestDO awardRequestDO = new AwardRequestDO();
        // 投放信息
        awardRequestDO.setDeliver(getRequestAwardParam.getDeliverMap());
        // 投放DTO
        awardRequestDO.setDeliverDTO(getRequestAwardParam.getDeliver());
        // 答卷信息
        awardRequestDO.setSurvey(getRequestAwardParam.getSurvey());
        return awardRequestDO;
    }

    /**
     * 获取奖励 校验失败 处理
     *
     * @param errorRequest 请求参数
     * @param checkResult  校验结果
     * @return 返回失败结果
     */
    protected ServiceResult<String> checkFail(AwardRequestDO errorRequest, AwardRequestStatusEnum checkResult) {
        errorRequest.setStatus(checkResult.getIndex());
        awardRequestDao.insert(errorRequest);
        return ServiceResult.fail(checkResult.getName());
    }

    /**
     * 根据id查询奖励请求记录
     *
     * @param requestId 请求记录id
     * @return 奖励请求记录
     */
    @Override
    public ServiceResult<AwardRequestDO> getAwardRequestById(String requestId) {
        AwardRequestDO awardRequestDO = awardRequestDao.findById(requestId);
        if (awardRequestDO != null) {
            return ServiceResult.success(awardRequestDO);
        }
        return ServiceResult.fail("请求记录不存在！");
    }

    /**
     * 判断是否需要手动上传兑奖码数据
     *
     * @param awardAwardDO 奖励
     * @return boolean
     */
    public boolean checkNeedCode(AwardAwardDO awardAwardDO) {
        Optional<Integer> total = Optional.of(awardAwardDO).map(AwardAwardDO::getBasic).map(AwardAwardDO.Basic::getTotalCount);
        if (total.isPresent() && total.get() > 0) {
            if (AwardTypeEnum.DRAW.getIndex() == awardAwardDO.getTType()) {
                Optional<Integer> issueMethod = Optional.of(awardAwardDO).map(AwardAwardDO::getIssue).map(AwardAwardDO.Issue::getMethod);
                Optional<String> prefix = Optional.of(awardAwardDO).map(AwardAwardDO::getIssue).map(AwardAwardDO.Issue::getPrefix);
                return (issueMethod.isPresent()
                        && AwardIssueTypeEnum.CODE.getIndex() == issueMethod.get()
                        && (!prefix.isPresent() || StrUtil.isEmpty(prefix.get())));
            } else if (AwardTypeEnum.NEW_DRAW.getIndex() == awardAwardDO.getTType()) {
                if (!CollectionUtils.isEmpty(awardAwardDO.getAwards())) {
                    for (AwardAwardDO.Award award : awardAwardDO.getAwards()) {
                        if (AwardIssueTypeEnum.CODE.getIndex() == award.getMethod() && StringUtils.isBlank(award.getPrefix())) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    @Override
    public ServiceResult<String> beforeFinishAward(String awardId) {
        return ServiceResult.success();
    }

    /**
     * 奖励创建后
     *
     * @param orgId     机构id
     * @param projectId 项目id
     * @param awardId   奖励id
     * @return
     */
    @Override
    public ServiceResult<String> afterAwardCreate(String orgId, String projectId, String awardId) {
        addProjectAwardCountCount(orgId, projectId, 1);
        awardCountRequestCacheService.initRequestCount(awardId, 0, 0);
        return ServiceResult.success();
    }

    /**
     * 修改项目下奖励数量
     *
     * @param orgId     公司id
     * @param projectId 项目id
     * @param count     数量 正加，负减
     */
    public Long addProjectAwardCountCount(String orgId, String projectId, int count) {
        String key = String.format(RedisKeyConstant.AWARD_COUNT_PROJECT, orgId, projectId);
        Object newCount = redisService.execute(increaseProjectAwardCountLua.getRedisScript(), Arrays.asList(key), count);
        if (newCount != null && (Long) newCount == -2) {
            log.info("[award] 项目奖励数量未初始化， 进行初始化.orgId:{},projectId:{}", orgId, projectId);
            newCount = initProjectAwardCount(orgId, projectId);
        } else if (newCount == null || (Long) newCount < 0 || (Long) newCount > Constants.AWARD_MAX_COUNT_PER_PROJECT) {
            log.error("[award] 项目奖励数量统计错误，重新统计.orgId:{},projectId:{},newCount:{}", orgId, projectId, newCount);
            newCount = initProjectAwardCount(orgId, projectId);
        }
        return (Long) newCount;
    }

    /**
     * 初始化项目下奖励数量
     *
     * @param orgId
     * @param projectId
     * @return
     */
    protected Long initProjectAwardCount(String orgId, String projectId) {
        String lockKey = String.format(RedisKeyConstant.AWARD_AWARD_OPERATE, orgId, projectId);
        redisService.lock(lockKey);
        try {
            String key = String.format(RedisKeyConstant.AWARD_COUNT_PROJECT, orgId, projectId);
            if (redisService.hasKey(key)) {
                return Long.valueOf(redisService.getString(key));
            }
            long count = awardAwardDao.countAwardAward(orgId, projectId, null, null);
            redisService.setIfAbsent(key, String.valueOf(count));
            return count;
        } finally {
            redisService.unlock(lockKey);
        }
    }

    /**
     * 奖励删除后
     *
     * @param orgId     机构id
     * @param projectId 项目id
     * @param awardId   奖励id
     * @return
     */
    @Override
    public ServiceResult<String> afterAwardDelete(String orgId, String projectId, String awardId) {
        addProjectAwardCountCount(orgId, projectId, -1);
        awardCountRequestCacheService.delRequestCount(awardId);
        return ServiceResult.success();
    }
}